package gamesrv

import (
	"context"
	"fmt"
	"net/http"
	"wanyu/operatorbackend/engine/wpcfg"
	"wanyu/server/engine/storage"
	"wanyu/server/engine/utils"
	"wanyu/server/plus/meta"
	"wanyu/server/plus/player"

	"github.com/micro/go-micro/config"

	//_ "net/http/pprof"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"
	gameCfg "wanyu/server/api/gameapi/gamecfg"
	"wanyu/server/api/gameapi/gamehandler"
	"wanyu/server/api/gameapi/roommgr"
	"wanyu/server/api/gameapi/session"
	cst "wanyu/server/engine/globaldef/consts"
	sa "wanyu/server/engine/serverapp"
	cfg "wanyu/server/engine/wpcfg"
	log "wanyu/server/engine/wplog"

	"github.com/micro/go-micro/client"
)

var mgoInstance *player.Database

type gameService struct {
	microSrvName string
	// micro service
	microSrv   sa.BaseService
	rpcSrvName string
	rpcSrv     sa.BaseService
	roomMgr    *roommgr.RoomMgr
}

//new服务示例
func NewService() sa.WindService {
	return &gameService{
		microSrvName: "gameapi",
		microSrv:     sa.NewBaseService(),
		rpcSrv:       sa.NewBaseService(),
	}
}

/*
	Init 初始化，主要做以下几件事:
	1. 服务配置初始化
	2. 初始化并注册rpc调用服务，用于grpc和roomsrv通信
	3. 初始化并注册流式服务，用于和gateway通信
	4. 初始化游戏配置包，用户游戏配置获取、解析、实时更新
	5. 初始化游戏逻辑管理模块（room包）
*/
func (gs *gameService) Init(context context.Context) (err error) {

	//读取配置
	var srvConfig sa.ServiceConf
	if ec := cfg.ScanNode(cst.ConfigServer, &srvConfig, "microservice"); nil != ec {
		return ec
	}

	//初始化micro类型微服务，用于rpc调用服务
	if ec := gs.microSrv.Init(sa.WithContext(context),
		sa.WithCfg(srvConfig),
		sa.WithServiceType(sa.MicroType),
		sa.WithQuitHandler(true),
		sa.WithCmdFunc(gs.onCmd)); nil != ec {
		return ec
	}

	{
		cfgFile := utils.GetCurDir() + "/" + gs.Name() + ".json"

		var cfg config.Config
		if cfg, err = wpcfg.SyncLoadFile(cst.ConfigServer, cfgFile); err != nil {
			return
		}

		var dbConfig storage.StorageConf
		if err = cfg.Get("database").Scan(&dbConfig); err != nil {
			return
		}

		meta.InitManager(dbConfig.StorageAddr)
		player.InitDatabase(dbConfig.StorageAddr, dbConfig.DataBase)
	}

	//解析游戏类型
	gameType := gameCfg.ParseGameType(srvConfig.SrvName)

	//生成和gw通信的微服务名，老的名字需要记录下来
	rawSrvName := srvConfig.SrvName
	srvConfig.SrvName = strings.Replace(srvConfig.SrvName, "wind.platform.api.", "wind.platform.api.gw-", -1)
	if ec := gs.rpcSrv.Init(sa.WithContext(context),
		sa.WithCfg(srvConfig),
		sa.WithServiceType(sa.GrpcType),
		sa.WithQuitHandler(true),
		sa.WithDisableDebugAddr(true)); nil != ec {
		return ec
	}

	//初始化流式通信
	clients := []client.Client{
		gs.microSrv.Client(),
		gs.microSrv.Client(),
		gs.microSrv.Client(),
	}
	if ec := session.Init(clients, 20); nil != ec {
		return ec
	}

	//初始化房间管理
	if gs.roomMgr = roommgr.Init(gameType, rawSrvName); nil == gs.roomMgr {
		return fmt.Errorf("init roommgr is failed")
	}

	//初始化rpc通信
	if ec := gamehandler.Init(gs.microSrv.Server(), gs.microSrv.Client(), gs.rpcSrv.Server(), gs.rpcSrv.Client(), gs.roomMgr); nil != ec {
		return ec
	}

	// 捕获进程退出事件
	channel := make(chan os.Signal, 1)
	signal.Notify(channel, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
	go func() {
		sig := <-channel
		log.Warn("catch process exit signal, prepare move to other gameapi, signal = ", sig)
		gs.roomMgr.OnProcessExit()
		time.Sleep(time.Millisecond * 300)
		log.Warn("move player to other gameapi is complete, exit process...")
		os.Exit(0)
	}()

	//启动调试端口
	// strGameType := ""
	// for k, v := range cst.GamesName {
	// 	if v == gameType {
	// 		strGameType = k
	// 		break
	// 	}
	// }
	// if "" == strGameType {
	// 	return fmt.Errorf("get str game type is failed, please check gameapi.json")
	// }
	// if value, err := cfg.Get(cst.ConfigServer, "debugport", strGameType); nil == err {
	// 	str := value.Bytes()
	// 	if len(str) > 0 {
	// 		if port, err2 := strconv.Atoi(string(str)); nil == err2 {
	// 			go func() {
	// 				if err = http.ListenAndServe(":"+strconv.Itoa(port), nil); nil != err {
	// 					log.Warn("start debug listen is failed, ec = ", err)
	// 				}
	// 			}()
	// 		}
	// 	}
	// }

	return nil
}

func (gs *gameService) onCmd(cmd string, param string) string {
	switch cmd {
	case "/i":
		rsp := gs.roomMgr.GetSummary()
		return fmt.Sprintf("R:%v, P:%v, RP:%v", rsp.TotalRoomCount, rsp.TotalPlayerCount, rsp.RealPlayerCount)

	case "/c":
		return "gameapi /c" + param

	default:
		return "unkown cmd"
	}
}

func (gs *gameService) Name() string {
	return gs.microSrvName
}

func (gs *gameService) RegisterHandler() {

}

func (gs *gameService) Run() error {
	retChan := make(chan error, 1)
	go func() {
		ec := gs.microSrv.Run()
		// select {}
		retChan <- ec
	}()
	go func() {
		ec := gs.rpcSrv.Run()
		retChan <- ec
	}()

	ec := <-retChan
	return ec
}

func (gs *gameService) Stop() error {
	return nil
}

func (gs *gameService) String() string {
	return ""
}

func (gs *gameService) Start() error {
	return nil
}
func (gs *gameService) Handle(pattern string, handler http.Handler) {
	gs.Handle(pattern, handler)
}
